/**
   EMMA = Estación Meteorológica de Muestreo Automática
 
 emma_project
 Copyright (C) 2015  Rodrigo Garcia

 This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

------------ Build ------------
   Use the 'Makefile' inside Build: make all

*/

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>

#include "usartio.h"
//#include "i2c.h"
//#include "rtcDS3231.h"
//#include "DataLogger.h"
#include "TimeChecker.h"
#include "UserSerialInterface.h"
#include "TC2.h"

// Coment the following line to disable debug
#define DEBUG_MODE
// Aditionally comment #define VERBOSE_FAT32 in SD_routines.h

char char_num_str[5];
char int_num_str[8];

volatile char timc2_interrupt_counter;

void Check_First_boot(void)
{
  if(EEPROM_read(0x00) == 0xFF) //means first boot for the system
    { // writes default values
      unsigned char i;
      for(i=100; i>=0; i--)
	EEPROM_write(i, 0x00); // erases previous data

      // default sampling time to 15 seconds
      EEPROM_write(TIME_INTERVAL_SEC, 15);
      EEPROM_write(TIME_INTERVAL_MIN, 0);
      EEPROM_write(TIME_INTERVAL_HOUR, 0);

      printf("1st Boot!");
      _delay_ms(3000);
    }
}

// ports initialization
void init_ports(void)
{ // see if it is ok
  PORTA = 0x00;
  DDRA = 0xFF;
  PORTB = 0xEF;
  DDRC  = 0x00;
  DDRB  = 0xBF; //MISO line i/p, rest o/p 
  PORTC = 0xFF;
  PORTD = 0x00;
  DDRD  = 0xFE;
}

// routine to init external devices
void init_devices(void)
{
  cli(); // interupts disabled
  init_ports();
  
  // -- peripherals initialization --
  // usart
  usart_printf_init(); //printf is initialized via usart

  // spi
  spi_init();
  // SD card
  unsigned char error = 0;
  do
    {
      error = SD_initialization();

#ifdef DEBUG_MODE
      if(error)
	{ 
	  if(error == 1) printf_P(PSTR("SD card not detected.."));
	  if(error == 2) printf_P(PSTR("Card Init failed.."));
	}
      else
	printf_P(PSTR("SD CARD found"));
#endif

      PORTD |= 1<<2; //LED ON
      _delay_ms(550);
      PORTD &= ~(1<<2); //LED off

    } while (error);
  // twi/i2c init
  i2c_init();
  // registers
  MCUCR = 0x00;
  GICR  = 0x00;
  TIMSK = 0x00; //timer interrupt sources
  // sensors
  InitializeSensors();
  // ----
}
// setup routine
void setup(void)
{
  init_ports();
  init_devices();

  set_sleep_mode(SLEEP_MODE_IDLE);
  cli();
    /*
    Here add sleep mode initialization to make the system save
    some energy.

    Since Timer/counter 2 is to be used to wake up the MCU
    every 32.768 ms , It will be used Idle mode (pag 33 datasheet).
    This mode stops CPU but allowing SPI, USART, Analog Comparator, ADC, Two-wire Serial Interface Timer/Counters, Watchdog, and the interrupt system to continue operating. This sleep
mode basically halts clk CPU and clk FLASH , while allowing the other clocks to run.
    Idle mode enables the MCU to also wake when Timer Overflow interrupt ocurs.

    To put the MCU in sleep mode:

    MCUCR|=(1<<SE) // this makes the MCU to enter in sleep mode when the SLEEP instruction is executed.
    (clear SE to avoid accidentaly entering to SLEEP mode)
    
    MCURC&=~(1<<SM2)|~(1<<SM1)|~(1<<SM0) // Idle mode

    Using avr-libc-1.8.0 macros (pag 311)

    #include <avr/interrupt.h>
    #include <avr/sleep.h>

    set_sleep_mode(mode);
    cli();
    if (some condition)
    { sleep_enable();
      sei(); // to be able to wake up the MCU by an interrupt
      sleep_cpu(); // put the MCU to sleep
      sleep_disable(); // This after the interruption routine was executed
    }
    sei();
  */
}

// -------------------------- Main program -----------------------
int main(void)
{
  _delay_ms(100);  //delay for VCC stabilization

  PORTD &= ~(1<<2); //LED off (sampling activated)

  setup();
  
  //struct RTC_time rtc_time;
  DS3231_get_time(&rtc_time);

  Check_First_boot();

  // To force update Table header (See Docu/datalog_format)
  change_table_header = 1;

  is_time_to_log = 0; // 1=true, 0=false

  // updates control registers from EEPROM
  UpdateFlagsFromEEPROM();

  // updates the configured sampling time interval
  UpdateConfiguredTimeFromEEPROM();

  // Data log File Structure
  // NOTE: Be careful and always intializate data_log struct
  struct LogFile data_log = {"00-00-00.l", "00:00:00"};  // dummy

  // sets the FileName to the current date.
  UpdateFileNameToCurrentDate(&data_log);
  printf("%s",data_log.FileName);

  // main bucle
  while(1)
  {
     // Check current time and sampling time interval
     CheckForConfiguredTime(&data_log);

     // === Serial User Interface ===
     if(! (PINC & (1<<2)) ) // CONFIG swtich selected
       {
	 PORTD |= 1<<2; //LED ON

	 // Call here serial interface routine (it is a loop)
	 SerialUserInterface();
	 
	 UpdateFileNameToCurrentDate(&data_log); // in case date was changed

	 PORTD &= ~(1<<2); //LED off
       }
     // ======

     /// ==== Prepare data to be logged  ====
     if(is_time_to_log)
       {
	 /// ==== Log the sample into file ====
	 // time update
	 sprintf(char_num_str, "%02d", rtc_time.hour);
	 Set_DatalogTime(&data_log, char_num_str, 0); // hh
	 Set_DatalogTime(&data_log, ":", 1); // hh:
	 sprintf(char_num_str, "%02d", rtc_time.min);
	 Set_DatalogTime(&data_log, char_num_str, 1); // hh:mm
	 Set_DatalogTime(&data_log, ":", 1); // hh:mm:
	 sprintf(char_num_str, "%02d", rtc_time.sec);
	 Set_DatalogTime(&data_log, char_num_str, 1); // hh:mm:ss

	 PORTD |= 1<<2; //LED on

	 // Read sensors and log into file
	 LogIntoFile(&data_log);
	 
	 PORTD &= ~(1<<2); //LED off

#ifdef DEBUG_MODE
	 printf("\n-- %s\n", data_log.FileName);
	 SD_readFile(data_log.FileName);
	 printf("\n--");
#endif

       }
     else
       {
	 timc2_interrupt_counter = 0;
	 sei(); // to be able to wake up the MCU by an interrupt

	 // 21 interrupts takes about 700 ms
	 while(timc2_interrupt_counter <= 21)
	   {
	     // putting the MCU to sleep mode to save energy
	     sleep_enable();

	     timc2_interrupt_counter = 0;
	     TC2_conf(timc2_prescaler1024);  // FCPU=8MHZ --> an averflow takes 32.768 ms
	     TC2_OV_ENABLE();

	     sleep_cpu(); // put the MCU to sleep, wakes up on TOV2
	   }
	 // After 21 TC2 ov interrupts, returns here
	 sleep_disable();
	 TC2_OV_DISABLE();
	 cli();

       }

/* #ifdef DEBUG_MODE */
/*     printf_P(PSTR("\nTIME:")); */
/*     printf("Reading response=%u\n", aux); */
/*     printf("%02u:%02u:%02u %02u-%02u-%02u", rtc_time.hour,rtc_time.min, */
/* 	   rtc_time.sec,rtc_time.mon, rtc_time.mday,rtc_time.year); */
/* #endif */

    /* ***************** DEBUG_MODE ***************** */
    /* In this mode individual devices can be tested by giving commands */
    /* via usart and the micro will answer results via usart too */
    /*   In the future a switch will put the system in debug mode, awaiting */
    /* queries from outside */
  }

  return 0;
}

// Interrupt routine Timer/Counter 2 Overflow
ISR(TIMER2_OVF_vect)
{
  timc2_interrupt_counter++;
}





















/* #ifdef DEBUG_MODE */
/*       unsigned char option, error, data, FAT32_active; */
/*       unsigned int i; */
/*       unsigned char fileName[13]; */

/*       char cc='a'; */
/*       while (cc!='q') // to test the Usart comunication */
/*       { */
/* 	  cc = usart_rx_1s(); */
/* 	  printf("\npress q to continue %c",cc); */
/* 	  printf_P(PSTR(" ..")); */
/*       } */

/*       printf_P(PSTR("\nStart!\n")); */

/*       cardType = 0; */

/*       // --- Testing the SD card initialization ---- */

/*       error = SD_initialization(); */

/*       if(error) */
/*       { */
/* 	  if(error == 1) printf_P(PSTR("SD card not detected..")); */
/* 	  if(error == 2) printf_P(PSTR("Card Init failed..")); */

/* 	  while(1);  //wait here forever if error in SD init */
/*       } */

/*       switch (cardType) */
/*       { */
/*       case 1:printf_P(PSTR("Std Cap Card(Ver 1.x)!")); */
/* 	  break; */
/*       case 2:printf_P(PSTR("H Cap Card!")); */
/* 	  break; */
/*       case 3:printf_P(PSTR("Std Cap Card(Ver 2.x)!")); */
/* 	  break; */
/*       default:printf_P(PSTR("Ukwn SD Card!")); */
/* 	  break; */
/*       } */


/*       SPI_HIGH_SPEED;	//SCK - 4 MHz */
/*       _delay_ms(1);   //some delay */

/*       FAT32_active = 1; */
/*       error = getBootSectorData (); //read boot sector and keep necessary data in global variables */
/*       if(error) */
/*       { */
/* 	  printf_P(PSTR("\nFAT32 not found!"));  //FAT32 incompatible drive */
/* 	  FAT32_active = 0; */
/*       } */

/*       while(1) */
/*       { */
/* 	  printf_P(PSTR("Press key\n")); */
/* 	  option = usart_rx(); */
/* 	  printf_P(PSTR("\n>0:Erase Blocks")); */
/* 	  printf_P(PSTR("\n>1:Write single Block")); */
/* 	  printf_P(PSTR("\n>2:Read single Block")); */

/* #ifndef FAT_TESTING_ONLY */
      
/* 	  printf_P(PSTR("\n>3:Write multiple Blocks")); */
      
/* 	  printf_P(PSTR("\n>4:Read multiple Blocks")); */
/* #endif */
      
/* 	  printf_P(PSTR("\n>5:file list")); */
      
/* 	  printf_P(PSTR("\n>6:Read File")); */
      
/* 	  printf_P(PSTR("\n>7:Write File")); */
      
/* 	  printf_P(PSTR("\n>8:Delete File")); */
      
/* 	  printf_P(PSTR("\n>9:Read SD Memory Capacity (Total/Free)")); */

/* 	  printf_P(PSTR("\n>Select Option (0-9):")); */


/* 	  /\*WARNING: If option 0, 1 or 3 is selected, the card may not be detected by PC/Laptop again, */
/* 	    as it disturbs the FAT format, and you may have to format it again with FAT32. */
/* 	    This options are given for learnig the raw data transfer to & from the SD Card*\/ */

/* 	  option = usart_rx(); */
/* 	  usart_tx(option); */

/* 	  if(option >=0x35 && option <=0x39)  //options 5 to 9 disabled if FAT32 not found */
/* 	  { */
/* 	      if(!FAT32_active) */
/* 	      { */
	      
/* 		  printf_P(PSTR("\nFAT32 options disabled!")); */
/* 		  continue; */
/* 	      } */
/* 	  } */


/* 	  if((option >= 0x30) && (option <=0x34)) //get starting block address for options 0 to 4 */
/* 	  { */
/* 	      printf_P(PSTR("\nEnter the Block number(0000-9999):")); */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      startBlock = (data & 0x0f) * 1000; */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      startBlock += (data & 0x0f) * 100; */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      startBlock += (data & 0x0f) * 10; */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      startBlock += (data & 0x0f); */
/* 	  } */

/* 	  totalBlocks = 1; */

/* #ifndef FAT_TESTING_ONLY */

/* 	  if((option == 0x30) || (option == 0x33) || (option == 0x34)) //get total number of blocks for options 0, 3 or 4 */
/* 	  { */
	  
	  
/* 	      printf_P(PSTR("\nHow many blocks?(000-999):")); */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      totalBlocks = (data & 0x0f) * 100; */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      totalBlocks += (data & 0x0f) * 10; */
/* 	      data = usart_rx(); usart_tx(data); */
/* 	      totalBlocks += (data & 0x0f); */
	  
/* 	  } */

/* #endif */

/* 	  switch (option) */
/* 	  { */
/* 	  case '0': //error = SD_erase (block, totalBlocks); */
/* 	      error = SD_erase (startBlock, totalBlocks); */
          
/* 	      if(error) */
/* 		  printf_P(PSTR("\nErase failed..")); */
/* 	      else */
/* 		  printf_P(PSTR("\nErased!")); */
/* 	      break; */

/* 	  case '1': */
/* 	      printf_P(PSTR("\nEnter text(End with~);")); */
/* 	      i=0; */
/* 	      do */
/* 	      { */
/* 		  data = usart_rx(); */
/* 		  usart_tx(data); */
/* 		  buffer[i++] = data; */
/* 		  if(data == 0x0d) */
/* 		  { */
/* 		      usart_tx(0x0a); */
/* 		      buffer[i++] = 0x0a; */
/* 		  } */
/* 		  if(i == 512) break; */
/* 	      }while (data != '~'); */

/* 	      error = SD_writeSingleBlock (startBlock); */
	  
	  
/* 	      if(error) */
/* 		  printf_P(PSTR("\nWrite failed!")); */
/* 	      else */
/* 		  printf_P(PSTR("\nWrite successful!")); */
/* 	      break; */

/* 	  case '2': error = SD_readSingleBlock (startBlock); */
          
/* 	      if(error) */
/* 		  printf_P(PSTR("\nRead failed!")); */
/* 	      else */
/* 	      { */
/* 		  for(i=0;i<512;i++) */
/* 		  { */
/* 		      if(buffer[i] == '~') break; */
/* 		      usart_tx(buffer[i]); */
/* 		  } */
	      
	      
/* 		  printf_P(PSTR("\nRead successful!")); */
/* 	      } */

/* 	      break; */
/* 	      //next two options will work only if following macro is cleared from SD_routines.h */
/* #ifndef FAT_TESTING_ONLY */

/* 	  case '3': */
/* 	      error = SD_writeMultipleBlock (startBlock, totalBlocks); */
          
/* 	      if(error) */
/* 		  printf_P(PSTR("\nWrite failed!")); */
/* 	      else */
/* 		  printf_P(PSTR("\nWrite successful!")); */
/* 	      break; */

/* 	  case '4': error = SD_readMultipleBlock (startBlock, totalBlocks); */
          
/* 	      if(error) */
/* 		  printf_P(PSTR("\nRead failed!")); */
/* 	      else */
/* 		  printf_P(PSTR("\nRead successful!")); */
/* 	      break; */
/* #endif */

/* 	  case '5': */
/* 	      SD_list_files(); */
/* 	      //	  findFiles(GET_LIST,0); */
/* 	      break; */

/* 	  case '6': */
/* 	  case '7': */
/* 	  case '8': */
	  
/* 	      printf_P(PSTR("\nEnter file name:")); */
/* 	      for(i=0; i<13; i++) */
/* 		  fileName[i] = 0x00;   //clearing any previously stored file name */
/* 	      i=0; */
/* 	      while(1) */
/* 	      { */
/* 		  data = usart_rx(); */
/* 		  if(data == 0x0d) break;  //'ENTER' key pressed */
/* 		  if(data == 0x08)	//'Back Space' key pressed */
/* 		  { */
/* 		      if(i != 0) */
/* 		      { */
/* 			  usart_tx(data); */
/* 			  usart_tx(' '); */
/* 			  usart_tx(data); */
/* 			  i--; */
/* 		      } */
/* 		      continue; */
/* 		  } */
/* 		  if(data <0x20 || data > 0x7e) continue;  //check for valid English text character */
/* 		  usart_tx(data); */
/* 		  fileName[i++] = data; */
/* 		  if(i==13) */
/* 		  { */
/* 		      printf_P(PSTR("\nfile name too long..")); */
/* 		      break; */
/* 		  } */
/* 	      } */
/* 	      if(i>12) break; */
       
	  
/* 	      if(option == '6') */
/* 		  SD_readFile(fileName); */
/* 	      //	    readFile( READ, fileName); */
/* 	      if(option == '7') */
/* 	      { */
/* 		  unsigned char cont[] = "\n\r--- DD/MM/YYYY , hh:mm:ss\r temp C (hs1101)\r humidity % (hs1101)\r magnetic_field G (sensor)"; */
/* 		  //SD_writeFile(fileName, cont); */
/* 		  SD_writeFile(fileName, cont); */
/* 		  //writeFile(fileName); */
/* 	      } */

/* 	      if(option == '8') */
/* 		  SD_deleteFile(fileName); */
/* 	      //	    deleteFile(fileName); */
/* 	      break; */

/* 	  case '9': memoryStatistics(); */
/* 	      break; */
/* 	  default: */
/* 	      printf_P(PSTR("\nInvalid option")); */

/* 	  } */
/* /\* ******************************************** *\/ */
/*       } */
/* #endif */

/*     } */


// ---------------------------------------------------------------
